#ifndef __CPIL_OPERATOR_HPP__
#define __CPIL_OPERATOR_HPP__

#include <sharedarray.hpp>
#include <iterator.hpp>
#include <image.hpp>


class Operator
{
    public:
        Operator() {}
};



class Convert : public Operator
{
    protected:

        template< typename DataTypeIn , typename DataTypeOut >
        inline void RGBtoGREY(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {
            Iterator<DataTypeOut>     dst(out);
            ConstIterator<DataTypeIn> src(in);

            for(unsigned int n=0 ; n < in.nbPixels() ; n++)
                *(dst++) = *(src++)*0.2125 + *(src++)*0.7154 + *(src++)*0.0721;
        }

        template< typename DataTypeIn , typename DataTypeOut >
        inline void RGBtoYUV(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void RGBtoXYZ(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void RGBtoCieLAB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void GREYtoRGB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {
            Iterator<DataTypeOut>     dst(out);
            ConstIterator<DataTypeIn> src(in);

            DataTypeIn value;

            for(unsigned int n=0 ; n < in.nbPixels() ; n++)
            {
                value = *(src++);
                *(dst++) = value;
                *(dst++) = value;
                *(dst++) = value;
            }
        }

        template< typename DataTypeIn , typename DataTypeOut >
        inline void GREYtoYUV(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void GREYtoXYZ(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void GREYtoCieLAB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}


        template< typename DataTypeIn , typename DataTypeOut >
        inline void YUVtoRGB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void YUVtoGREY(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void YUVtoXYZ(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void YUVtoCieLAB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void XYZtoRGB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void XYZtoGREY(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void XYZtoYUV(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void XYZtoCieLAB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void CieLABtoRGB(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void CieLABtoGREY(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void CieLABtoYUV(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void CieLABtoXYZ(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {}

        template< typename DataTypeIn , typename DataTypeOut >
        inline void simpleCopy(const Image<DataTypeIn> &in, Image<DataTypeOut> &out) const
        {
            cout<<"ok simple copy"<<endl;
            Iterator<DataTypeOut>     dst(out);
            ConstIterator<DataTypeIn> src(in);

            for(unsigned int n=0 ; n < in.getSize() ; n++)
                *(dst++) = *(src++);
        }

    public:

        template< typename DataTypeIn , typename DataTypeOut >
        Convert(const Image<DataTypeIn> &in, Image<DataTypeOut> &out)
        {
            ColorModel * fromColorSpace( in.getColorModel()),
                       *   toColorSpace(out.getColorModel());

            if( fromColorSpace && toColorSpace)
            {
                out.setSize(in.getWidth(),in.getHeight(),out.getColorModel());

                if( fromColorSpace == toColorSpace )
                    simpleCopy(in,out);
                else if( fromColorSpace == RGB_SPACE )
                {
                    if( toColorSpace == GREY_SPACE )
                        RGBtoGREY(in,out);
                    else if ( toColorSpace == YUV_SPACE )
                        RGBtoYUV(in,out);
                    else if ( toColorSpace == XYZ_SPACE )
                        RGBtoXYZ(in,out);
                    else if ( toColorSpace == CIELAB_SPACE )
                        RGBtoCieLAB(in,out);
                }
                else if( fromColorSpace == GREY_SPACE )
                {
                    if( toColorSpace == RGB_SPACE )
                        GREYtoRGB(in,out);
                    else if ( toColorSpace == YUV_SPACE )
                        GREYtoYUV(in,out);
                    else if ( toColorSpace == XYZ_SPACE )
                        GREYtoXYZ(in,out);
                    else if ( toColorSpace == CIELAB_SPACE )
                        GREYtoCieLAB(in,out);
                }
                else if( fromColorSpace == YUV_SPACE )
                {
                    if( toColorSpace == RGB_SPACE )
                        YUVtoRGB(in,out);
                    else if ( toColorSpace == GREY_SPACE )
                        YUVtoGREY(in,out);
                    else if ( toColorSpace == XYZ_SPACE )
                        YUVtoXYZ(in,out);
                    else if ( toColorSpace == CIELAB_SPACE )
                        YUVtoCieLAB(in,out);
                }
                else if( fromColorSpace == XYZ_SPACE )
                {
                    if( toColorSpace == RGB_SPACE )
                        XYZtoRGB(in,out);
                    else if ( toColorSpace == GREY_SPACE )
                        XYZtoGREY(in,out);
                    else if ( toColorSpace == YUV_SPACE )
                        XYZtoYUV(in,out);
                    else if ( toColorSpace == CIELAB_SPACE )
                        XYZtoCieLAB(in,out);
                }
                else if( fromColorSpace == CIELAB_SPACE )
                {
                    if( toColorSpace == RGB_SPACE )
                        CieLABtoRGB(in,out);
                    else if ( toColorSpace == GREY_SPACE )
                        CieLABtoGREY(in,out);
                    else if ( toColorSpace == YUV_SPACE )
                        CieLABtoYUV(in,out);
                    else if ( toColorSpace == XYZ_SPACE )
                        CieLABtoXYZ(in,out);
                }
            }
        }

        template< typename DataTypeIn >
        Convert(Image<DataTypeIn> &img, ColorModel * colorModel)
        {
            Image<DataTypeIn> res(colorModel);
            Convert(img,res);
            img=res;
        }

};

#endif
